/**
 * 内存分析器 - 跟踪安装过程中的内存使用情况
 * 帮助识别内存泄漏并优化资源使用
 */

const v8 = require("v8");

class MemoryProfiler {
    constructor() {
        this.checkpoints = [];
        this.startTime = Date.now();
        this.peakMemory = 0;
    }

    /**
     * 创建内存检查点
     * @param {string} label - 检查点标签
     */
    checkpoint(label) {
        const memUsage = process.memoryUsage();
        const heapStats = v8.getHeapStatistics();

        const checkpoint = {
            label,
            timestamp: Date.now() - this.startTime,
            memory: {
                rss: this.formatBytes(memUsage.rss),
                heapTotal: this.formatBytes(memUsage.heapTotal),
                heapUsed: this.formatBytes(memUsage.heapUsed),
                external: this.formatBytes(memUsage.external),
                arrayBuffers: this.formatBytes(memUsage.arrayBuffers || 0),
            },
            heap: {
                totalHeapSize: this.formatBytes(heapStats.total_heap_size),
                usedHeapSize: this.formatBytes(heapStats.used_heap_size),
                heapSizeLimit: this.formatBytes(heapStats.heap_size_limit),
                mallocedMemory: this.formatBytes(heapStats.malloced_memory),
                externalMemory: this.formatBytes(heapStats.external_memory),
            },
            raw: {
                heapUsed: memUsage.heapUsed,
            },
        };

        // Track peak memory
        if (memUsage.heapUsed > this.peakMemory) {
            this.peakMemory = memUsage.heapUsed;
        }

        this.checkpoints.push(checkpoint);
        return checkpoint;
    }

    /**
     * 强制垃圾回收 (需要 --expose-gc 标志)
     */
    forceGC() {
        if (global.gc) {
            global.gc();
            return true;
        }
        return false;
    }

    /**
     * 获取内存使用摘要
     */
    getSummary() {
        const currentMemory = process.memoryUsage();

        return {
            currentUsage: {
                rss: this.formatBytes(currentMemory.rss),
                heapTotal: this.formatBytes(currentMemory.heapTotal),
                heapUsed: this.formatBytes(currentMemory.heapUsed),
            },
            peakMemory: this.formatBytes(this.peakMemory),
            totalCheckpoints: this.checkpoints.length,
            runTime: `${((Date.now() - this.startTime) / 1000).toFixed(2)}s`,
        };
    }

    /**
     * 获取内存使用详细报告
     */
    getDetailedReport() {
        const summary = this.getSummary();
        const memoryGrowth = this.calculateMemoryGrowth();

        return {
            summary,
            memoryGrowth,
            checkpoints: this.checkpoints,
            recommendations: this.getRecommendations(memoryGrowth),
        };
    }

    /**
     * 计算检查点之间的内存增长
     */
    calculateMemoryGrowth() {
        if (this.checkpoints.length < 2) return [];

        const growth = [];
        for (let i = 1; i < this.checkpoints.length; i++) {
            const prev = this.checkpoints[i - 1];
            const curr = this.checkpoints[i];

            const heapDiff = curr.raw.heapUsed - prev.raw.heapUsed;

            growth.push({
                from: prev.label,
                to: curr.label,
                heapGrowth: this.formatBytes(Math.abs(heapDiff)),
                isIncrease: heapDiff > 0,
                timeDiff: `${((curr.timestamp - prev.timestamp) / 1000).toFixed(2)}s`,
            });
        }

        return growth;
    }

    /**
     * 根据内存使用情况获取建议
     */
    getRecommendations(memoryGrowth) {
        const recommendations = [];

        // Check for large memory growth
        const largeGrowths = memoryGrowth.filter((g) => {
            const bytes = this.parseBytes(g.heapGrowth);
            return bytes > 50 * 1024 * 1024; // 50MB
        });

        if (largeGrowths.length > 0) {
            recommendations.push({
                type: "warning",
                message: `在 ${largeGrowths.length} 个操作中检测到大量内存增长`,
                details: largeGrowths.map(
                    (g) => `${g.from} → ${g.to}: ${g.heapGrowth}`
                ),
            });
        }

        // Check peak memory
        if (this.peakMemory > 500 * 1024 * 1024) {
            // 500MB
            recommendations.push({
                type: "warning",
                message: `内存峰值使用过高: ${this.formatBytes(this.peakMemory)}`,
                suggestion: "考虑分批处理文件",
            });
        }

        // Check for potential memory leaks
        const continuousGrowth = this.checkContinuousGrowth();
        if (continuousGrowth) {
            recommendations.push({
                type: "error",
                message: "检测到潜在的内存泄漏",
                details: "内存使用量持续增加而没有明显减少",
            });
        }

        return recommendations;
    }

    /**
     * 检查持续内存增长 (潜在泄漏)
     */
    checkContinuousGrowth() {
        if (this.checkpoints.length < 5) return false;

        let increasingCount = 0;
        for (let i = 1; i < this.checkpoints.length; i++) {
            if (
                this.checkpoints[i].raw.heapUsed >
                this.checkpoints[i - 1].raw.heapUsed
            ) {
                increasingCount++;
            }
        }

        // If memory increases in more than 80% of checkpoints, might be a leak
        return increasingCount / (this.checkpoints.length - 1) > 0.8;
    }

    /**
     * 将字节格式化为人类可读的字符串
     */
    formatBytes(bytes) {
        if (bytes === 0) return "0 B";

        const k = 1024;
        const sizes = ["B", "KB", "MB", "GB"];
        const i = Math.floor(Math.log(bytes) / Math.log(k));

        return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + " " + sizes[i];
    }

    /**
     * 将人类可读的字节字符串解析回数字
     */
    parseBytes(str) {
        const match = str.match(/^([\d.]+)\s*([KMGT]?B?)$/i);
        if (!match) return 0;

        const value = parseFloat(match[1]);
        const unit = match[2].toUpperCase();

        const multipliers = {
            B: 1,
            KB: 1024,
            MB: 1024 * 1024,
            GB: 1024 * 1024 * 1024,
        };

        return value * (multipliers[unit] || 1);
    }

    /**
     * 清除检查点以释放内存
     */
    clear() {
        this.checkpoints = [];
    }
}

// Export singleton instance
module.exports = new MemoryProfiler();
